home *** CD-ROM | disk | FTP | other *** search
/ PC Media 7 / PC MEDIA CD07.iso / share / prog / cm / cmthash.cc < prev    next >
Encoding:
C/C++ Source or Header  |  1994-09-06  |  10.0 KB  |  411 lines

  1. // CmTHash.cc
  2. // -----------------------------------------------------------------
  3. // Compendium - C++ Container Class Library
  4. // Copyright (C) 1992-1994, Glenn M. Poorman, All rights reserved
  5. // -----------------------------------------------------------------
  6. // Hash table template implementation.
  7. // -----------------------------------------------------------------
  8.  
  9.  
  10. // "CmTHashTable" is the hash table constructor.
  11. //
  12. template <class T> CmTHashTable<T>::CmTHashTable(unsigned sz)
  13. {
  14.   _funcSet = FALSE;
  15.   _total   = 0;
  16.   _buckets = new CmTHashBucket<T>[sz];
  17.   _size    = (_buckets != NULL) ? sz : 0;
  18. }
  19.  
  20.  
  21. // "CmTHashTable" is the hash table copy constructor.
  22. //
  23. template <class T> CmTHashTable<T>::CmTHashTable(const CmTHashTable<T>& Tb)
  24.                                   : CmTContainer<T>(Tb)
  25. {
  26.   _funcSet = Tb._funcSet;
  27.   _hFunc   = Tb._hFunc;
  28.   _total   = 0;
  29.   _buckets = new CmTHashBucket<T>[Tb._size];
  30.   _size    = (_buckets != NULL) ? Tb._size : 0;
  31.   copy(Tb);
  32. }
  33.  
  34.  
  35. // "CmTHashTable" is the hash table destructor.
  36. //
  37. template <class T> CmTHashTable<T>::~CmTHashTable()
  38. {
  39.   removeAll();
  40.   delete[] _buckets;
  41. }
  42.  
  43.  
  44. // "=" assignment operator copies the specified hash table into this table.
  45. //
  46. template <class T>
  47. CmTHashTable<T>& CmTHashTable<T>::operator=(const CmTHashTable<T>& Tb)
  48. {
  49.   if (&Tb != this)
  50.   {
  51.     removeAll();
  52.     delete[] _buckets;
  53.     _funcSet = Tb._funcSet;
  54.     _hFunc   = Tb._hFunc;
  55.     _total   = 0;
  56.     _buckets = new CmTHashBucket<T>[Tb._size];
  57.     _size    = (_buckets != NULL) ? Tb._size : 0;
  58.     copy(Tb);
  59.   }
  60.   return *this;
  61. }
  62.  
  63.  
  64. // "setHashFunction" sets the hash function to be used on the input items.
  65. //
  66. template <class T> void
  67. CmTHashTable<T>::setHashFunction(unsigned (*pFunc)(const T&, unsigned))
  68. {
  69.   _funcSet = TRUE;
  70.   _hFunc   = pFunc;
  71. }
  72.  
  73.  
  74. // "total" returns the number of items in the table.
  75. //
  76. template <class T> int CmTHashTable<T>::total() const
  77. {
  78.   return _total;
  79. }
  80.  
  81.  
  82. // "add" adds a new item to the table.
  83. //
  84. template <class T> Bool CmTHashTable<T>::add(const T& rObj)
  85. {
  86.   if (!_funcSet) return FALSE;
  87.   unsigned idx = (*_hFunc)(rObj, _size);
  88.   Bool success = _buckets[idx].append(rObj);
  89.   if (success) _total++;
  90.   return success;
  91. }
  92.  
  93.  
  94. // "remove" removes the first occurrence of an item equal to the specified
  95. // item from the table.
  96. //
  97. template <class T> Bool CmTHashTable<T>::remove(const T& rObj)
  98. {
  99.   if (!_funcSet) return FALSE;
  100.   unsigned idx = (*_hFunc)(rObj, _size);
  101.   Bool success = _buckets[idx].remove(rObj);
  102.   if (success) _total--;
  103.   return success;
  104. }
  105.  
  106.  
  107. // "lookup" returns the first occurrence of an item equal to the specified
  108. // item.
  109. //
  110. template <class T> const T& CmTHashTable<T>::lookup(const T& rObj) const
  111. {
  112.   if (!_funcSet) return _error;
  113.   unsigned idx = (*_hFunc)(rObj, _size);
  114.   T* out = _buckets[idx].lookup(rObj);
  115.   return (out) ? *out : _error;
  116. }
  117.  
  118.  
  119. // "contains" checks if an item equal to the specified item exists
  120. // in the table.
  121. //
  122. template <class T> Bool CmTHashTable<T>::contains(const T& rObj) const
  123. {
  124.   if (!_funcSet) return FALSE;
  125.   unsigned idx = (*_hFunc)(rObj, _size);
  126.   return _buckets[idx].contains(rObj);
  127. }
  128.  
  129.  
  130. // "occurrences" counts the number of items in the table equal to the
  131. // specified item.
  132. //
  133. template <class T> unsigned CmTHashTable<T>::occurrences(const T& rObj) const
  134. {
  135.   CmTHashTableIterator<T> iterator(*this);
  136.   unsigned                num = 0;
  137.   while (!iterator.done())
  138.     if (iterator.next() == rObj) num++;
  139.   return num;
  140. }
  141.  
  142.  
  143. // "removeAll" removes all items from the table.
  144. //
  145. template <class T> void CmTHashTable<T>::removeAll()
  146. {
  147.   for (int ii = 0; ii < _size; ii++)
  148.     _buckets[ii].removeAll();
  149.   _total = 0;
  150. }
  151.  
  152.  
  153. // "resize" resizes the hash table.
  154. //
  155. template <class T> Bool CmTHashTable<T>::resize(unsigned newSize)
  156. {
  157.   if (newSize <= 0) newSize = 1;
  158.  
  159.   int               newTotal   = 0;
  160.   CmTHashBucket<T> *newBuckets = new CmTHashBucket<T>[newSize];
  161.   if (!newBuckets) return FALSE;
  162.  
  163.   CmTHashTableIterator<T> iterator(*this);
  164.   while (!iterator.done())
  165.   {
  166.     T   item = iterator.next();
  167.     int idx  = (*_hFunc)(item, newSize);
  168.     newBuckets[idx].append(item);
  169.     newTotal++;
  170.   }
  171.  
  172.   delete[] _buckets;
  173.   _size    = newSize;
  174.   _buckets = newBuckets;
  175.   _total   = newTotal;
  176.   return TRUE;
  177. }
  178.  
  179. // "isEmpty" checks whether or not the table is empty.
  180. //
  181. template <class T> Bool CmTHashTable<T>::isEmpty() const
  182. {
  183.   Bool empty = TRUE;
  184.   int  ii    = 0;
  185.   while (ii < _size && empty == TRUE)
  186.     if (_buckets[ii].size() > 0) empty = FALSE;
  187.   return empty;
  188. }
  189.  
  190.  
  191. // "newIterator" creates and returns a new table iterator.
  192. //
  193. template <class T> CmTIterator<T>* CmTHashTable<T>::newIterator() const
  194. {
  195.   return new CmTHashTableIterator<T>(*this);
  196. }
  197.  
  198.  
  199. // "append" appends a new item to the hash bucket.
  200. //
  201. template <class T> Bool CmTHashBucket<T>::append(const T& rObj)
  202. {
  203.   CmTHashNode<T> *newnode = new CmTHashNode<T>(rObj);
  204.   if (!newnode) return FALSE;
  205.  
  206.   if (!_first)
  207.     _first = _last = newnode;
  208.   else
  209.   {
  210.     _last->_next = newnode;
  211.     _last        = newnode;
  212.   }
  213.   _size++;
  214.   return TRUE;
  215. }
  216.  
  217.  
  218. // "contains" checks if an item equal to the specified item exists
  219. // in this hash bucket.
  220. //
  221. template <class T> Bool CmTHashBucket<T>::contains(const T& rObj) const
  222. {
  223.   CmTHashNode<T> *rover = _first;
  224.   Bool            found = FALSE;
  225.   while (rover && !found)
  226.   {
  227.     if (rover->_data == rObj) found = TRUE;
  228.     else                      rover = rover->_next;
  229.   }
  230.   return found;
  231. }
  232.  
  233.  
  234. // "remove" removes the first occurrence of an item equal to the
  235. // specified item from this hash bucket.
  236. //
  237. template <class T> Bool CmTHashBucket<T>::remove(const T& rObj)
  238. {
  239.   if (!_first) return FALSE;
  240.  
  241.   if (_first->_data == rObj)                // Object is first in the list.
  242.   {
  243.     CmTHashNode<T> *temp = _first;
  244.     if (_first == _last) _first = _last = NULL;
  245.     else                 _first = _first->_next;
  246.     _size--;
  247.     delete temp;
  248.     return TRUE;
  249.   }
  250.  
  251.   CmTHashNode<T> *rover1 = _first;          // Search for object in list.
  252.   CmTHashNode<T> *rover2 = _last;
  253.  
  254.   while (rover1 != NULL && rover1->_data != rObj)
  255.   {
  256.     rover2 = rover1;
  257.     rover1 = rover1->_next;
  258.   }
  259.  
  260.   if (rover1 == NULL) return FALSE;         // Object was not found.
  261.  
  262.   if (rover1 == _last)                      // Object is last in list.
  263.   {
  264.     _last         = rover2;
  265.     rover2->_next = NULL;
  266.   }
  267.  
  268.   else                                      // Remove object from list.
  269.     rover2->_next = rover2->_next->_next;
  270.  
  271.   delete rover1;                            // Delete the hash node.
  272.   return TRUE;
  273. }
  274.  
  275.  
  276. // "lookup" returns the first occurrence of an item equal to the
  277. // specified item.
  278. //
  279. template <class T> T* CmTHashBucket<T>::lookup(const T& rObj) const
  280. {
  281.   CmTHashNode<T> *rover = _first;
  282.   CmTHashNode<T> *temp  = NULL;
  283.   while (rover && !temp)
  284.   {
  285.     if (rover->_data == rObj)
  286.       temp = rover;
  287.     else
  288.       rover = rover->_next;
  289.   }
  290.   return (temp) ? &(temp->_data) : NULL;
  291. }
  292.  
  293.  
  294. // "removeAll" removes all items from this hash bucket.
  295. //
  296. template <class T> void CmTHashBucket<T>::removeAll()
  297. {
  298.   CmTHashNode<T> *temp, *rover = _first;
  299.   while (rover)
  300.   {
  301.     temp = rover->_next;
  302.     delete rover;
  303.     rover = temp;
  304.   }
  305.   _size  = 0;
  306.   _first = _last = NULL;
  307. }
  308.  
  309.  
  310. // "CmTHashTableIterator" is the iterator constructor.  The node
  311. // pointer is positioned at the first bucket containing items.
  312. //
  313. template <class T>
  314. CmTHashTableIterator<T>::CmTHashTableIterator(const CmTHashTable<T>& Tb)
  315.                         : _table(Tb), _bucket(0), _node(NULL)
  316. {
  317.   while (_table._buckets[_bucket]._size == 0 && _bucket < _table._size)
  318.     _bucket++;
  319.   if (_bucket < _table._size) _node = _table._buckets[_bucket]._first;
  320. }
  321.  
  322.  
  323. // "done" checks if the iterator can advance any further.
  324. //
  325. template <class T> Bool CmTHashTableIterator<T>::done() const
  326. {
  327.   return (!_node);
  328. }
  329.  
  330.  
  331. // "next" returns the current item and advances the iterator to the
  332. // next item.
  333. //
  334. template <class T> const T& CmTHashTableIterator<T>::next()
  335. {
  336.   if (!_node) return _table._error;
  337.  
  338.   const T& rObj = _node->_data;         // Save current item reference.
  339.  
  340.   if (_node->_next)                     // Advance to next node.
  341.     _node = _node->_next;
  342.   else                                  // Advance to next bucket with items.
  343.   {
  344.     _bucket++;
  345.     while (_bucket < _table._size && _table._buckets[_bucket]._size == 0)
  346.       _bucket++;
  347.     if (_bucket < _table._size) _node = _table._buckets[_bucket]._first;
  348.     else                        _node = NULL;
  349.   }
  350.   return rObj;
  351. }
  352.  
  353.  
  354. // "previous" decrements the iterator by one object and then returns
  355. // that object.
  356. //
  357. template <class T> const T& CmTHashTableIterator<T>::previous()
  358. {
  359.   if (!_node) return _table._error;
  360.   const T& rval = _node->_data;
  361.  
  362.   if (_node == _table._buckets[_bucket]._first)
  363.   {
  364.     --_bucket;
  365.     while (_bucket >= 0 && _table._buckets[_bucket]._size == 0)
  366.       _bucket--;
  367.     if (_bucket >= 0) _node = _table._buckets[_bucket]._last;
  368.     else              _node = NULL;
  369.   }
  370.   else
  371.   {
  372.     CmTHashNode<T> *rover = _table._buckets[_bucket]._first;
  373.     while (rover && rover->_next != _node)
  374.       rover = rover->_next;
  375.     _node = rover;
  376.   }
  377.   return rval;
  378. }
  379.  
  380.  
  381. // "current" returns the current object.
  382. //
  383. template <class T> const T& CmTHashTableIterator<T>::current() const
  384. {
  385.   return (_node) ? _node->_data : _table._error;
  386. }
  387.  
  388.  
  389. // "first" moves the iterator to the first item.
  390. //
  391. template <class T> void CmTHashTableIterator<T>::first()
  392. {
  393.   _bucket = 0;
  394.   _node   = NULL;
  395.   while (_table._buckets[_bucket]._size == 0 && _bucket < _table._size)
  396.     _bucket++;
  397.   if (_bucket < _table._size) _node = _table._buckets[_bucket]._first;
  398. }
  399.  
  400.  
  401. // "last" moves the iterator to the last item.
  402. //
  403. template <class T> void CmTHashTableIterator<T>::last()
  404. {
  405.   _bucket = _table._size - 1;
  406.   _node   = NULL;
  407.   while (_bucket >= 0 && _table._buckets[_bucket]._size == 0)
  408.     _bucket--;
  409.   if(_bucket >= 0) _node = _table._buckets[_bucket]._last;
  410. }
  411.